﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Threading;
using System.IO;
using System.Reflection;
using System.Web;
using System.Diagnostics;
using MvcEngine.Core.Utils;
using MvcEngine.Core.Exceptions;
using MvcEngine.Core.Extensions;
using System.Web.Hosting;
using MvcEngine.Core.Common;
using MvcEngine.Core.Helpers;

namespace MvcEngine.Core.Localization
{
    public class ResourceReader : IResourceReader
    {
        protected string[] resourceLocationFormats = new[]
        {
            "~/Modules/{2}/Areas/{1}/Content/Strings{0}.resx",
            "~/Modules/{2}/Areas/{1}/Content/Strings.resx",
            "~/Areas/{1}/Content/Strings{0}.resx",
            "~/Areas/{1}/Content/Strings.resx"
        };

        public static IResourceReader Current
        {
            get { return IoC.Resolve<IResourceReader>(); }
        }

        #region Public functions

        public virtual string GetString(string key, string defaultValue)
        {
            string result;
            if (TryGetString(key, out result))
                return result;
            return defaultValue;
        }

        public virtual string GetString(string key)
        {
            return GetString(key, false);
        }

        public virtual string GetString(string key, bool throwException)
        {
            string result = GetThreadSettingsValue(key);
            if (result != null)
                return result;
            if (throwException)
                throw new LocalizationException(key, resourceLocationFormats);
            return key;
        }

        public virtual bool TryGetString(string key, out string result)
        {
            result = GetThreadSettingsValue(key);
            if (result != null)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region Private methods

        private string GetThreadSettingsValue(string key)
        {
            List<string> searchedLocations = new List<string>();
            foreach (string locationFormat in resourceLocationFormats)
            {
                string path = string.Format(locationFormat, "." + Thread.CurrentThread.CurrentCulture.ToString(), HttpContext.Current.Items["Area"], HttpContext.Current.Items["moduleName"]);
                searchedLocations.Add(path);
                if (HostingEnvironment.VirtualPathProvider.FileExists(path))
                {
                    string result = GetValue(HttpContext.Current.Server.MapPath(path), key);
                    if (!string.IsNullOrEmpty(result))
                        return result;
                }
            }
            LogHelper.Current.WriteWarning(string.Format("Key {0} was not found in the localization file. Locations searched: {1}", key, searchedLocations.ConvertToString()));
            return null;
        }

        private string GetValue(string resourceFilePath, string key)
        {
            if (!File.Exists(resourceFilePath))
                return null;

            XDocument doc = LoadDocument(resourceFilePath);
            XElement val = doc.Root.Elements("data").FirstOrDefault(r => r.Attribute("name").Value == key);
            return val == null ? null : val.Element("value").Value;
        }

        private XDocument LoadDocument(string resourceFilePath)
        {
            if (HttpContext.Current.Cache[resourceFilePath] == null)
            {
                XDocument doc = XDocument.Load(resourceFilePath);
                HttpContext.Current.Cache[resourceFilePath] = doc;
                return doc;
            }
            else
            {
                return (XDocument)HttpContext.Current.Cache[resourceFilePath];
            }
        }

        #endregion
    }
}
